﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;

namespace 文件编码批量转换
{
    public partial class MainFrm : Form
    {
        public MainFrm()
        {
            InitializeComponent();
        }
        // 浏览...
        string[] filesNotUTF8 = { };
        private void button1_Click(object sender, EventArgs e)
        {
            string dirPath = "";
            FolderBrowserDialog fdlog = new FolderBrowserDialog();
            if (fdlog.ShowDialog() == DialogResult.OK)
            {
                this.txtPath.Text = fdlog.SelectedPath;
                dirPath = fdlog.SelectedPath;
                FileNotUtf8(dirPath);
                for (int i = 0; i < filesNotUTF8.Length; i++)
                {
                    string fileName = Path.GetFileNameWithoutExtension(filesNotUTF8[i]);
                    WriteLog(ImgConst.SUCC, fileName);
                }
                if (filesNotUTF8.Length > 0)
                {
                    label2.Text = "在指定目录下有" + filesNotUTF8.Length + "个 非 UTF8 字符集文件！";
                    button2.Enabled = true;
                }
                else
                {
                    label2.Text = "";
                    button2.Enabled = false;
                }
            }
        }

        public void FileNotUtf8(string dirPath)
        {
            //一级目录
            DirectoryInfo mydir = new DirectoryInfo(dirPath);
            string[] temp = FindNoUTF8File(dirPath);
            filesNotUTF8 = MergerArray(filesNotUTF8, temp);
            // 二级目录
            DirectoryInfo[] dirArr = mydir.GetDirectories();
            for (int j = 0; j < dirArr.Length; j++)
            {
                FileNotUtf8(dirArr[j].FullName);
            }
        }
        // 转换
        System.Text.Encoding GB2312 = System.Text.Encoding.GetEncoding("GB2312");
        System.Text.Encoding UTF8 = System.Text.Encoding.UTF8;
        private void button2_Click(object sender, EventArgs e)
        {
            txtPath.Enabled = false;
            button1.Enabled = false;
            button2.Enabled = false;
            try
            {

                foreach (string destfile in filesNotUTF8)
                {
                    if (destfile.Length > 0)
                        File.WriteAllText(destfile, File.ReadAllText(destfile, Encoding.Default), UTF8);

                }
                MessageBox.Show("转换成功！");
            }
            catch (Exception ex)
            {
                WriteLog(ImgConst.WARN, ex.Message);
            }

            txtPath.Enabled = true;
            button1.Enabled = true;
            button2.Enabled = true;
        }
        #region 返回指定目录下的非 UTF8 字符集文件
        /// <summary>
        /// 合并数组
        /// </summary>
        /// <param name="First">第一个数组</param>
        /// <param name="Second">第二个数组</param>
        /// <returns>合并后的数组(第一个数组+第二个数组，长度为两个数组的长度)</returns>
        public string[] MergerArray(string[] First, string[] Second)
        {
            string[] result = new string[First.Length + Second.Length];
            First.CopyTo(result, 0);
            Second.CopyTo(result, First.Length);
            return result;
        }

        /// <summary>
        /// 返回指定目录下的非 UTF8 字符集文件
        /// </summary>
        /// <param name="Path">路径</param>
        /// <returns>文件名的字符串数组</returns>
        public static string[] FindNoUTF8File(string Path)
        {
            StringBuilder filelist = new StringBuilder();
            DirectoryInfo Folder = new DirectoryInfo(Path);
            FileInfo[] subFiles = Folder.GetFiles();

            for (int j = 0; j < subFiles.Length; j++)
            {
                if (subFiles[j].Extension.ToLower().Equals(".cs") || subFiles[j].Extension.ToLower().Equals(".designer.cs"))
                {
                    FileStream fs = new FileStream(subFiles[j].FullName, FileMode.Open, FileAccess.Read);
                    bool bUtf8 = IsUTF8(fs);
                    fs.Close();
                    if (!bUtf8)
                    {
                        filelist.Append(subFiles[j].FullName);
                        filelist.Append("\r\n");
                    }
                }
            }
            return SplitString(filelist.ToString(), "\r\n");
        }

        //0000 0000-0000 007F - 0xxxxxxx  (ascii converts to 1 octet!)
        //0000 0080-0000 07FF - 110xxxxx 10xxxxxx    ( 2 octet format)
        //0000 0800-0000 FFFF - 1110xxxx 10xxxxxx 10xxxxxx (3 octet format)

        /// <summary>
        /// 判断文件流是否为UTF8字符集
        /// </summary>
        /// <param name="sbInputStream">文件流</param>
        /// <returns>判断结果</returns>
        private static bool IsUTF8(FileStream sbInputStream)
        {
            int i;
            byte cOctets;  // octets to go in this UTF-8 encoded character 
            byte chr;
            bool bAllAscii = true;
            long iLen = sbInputStream.Length;

            cOctets = 0;
            for (i = 0; i < iLen; i++)
            {
                chr = (byte)sbInputStream.ReadByte();

                if ((chr & 0x80) != 0) bAllAscii = false;

                if (cOctets == 0)
                {
                    if (chr >= 0x80)
                    {
                        do
                        {
                            chr <<= 1;
                            cOctets++;
                        }
                        while ((chr & 0x80) != 0);

                        cOctets--;
                        if (cOctets == 0)
                            return false;
                    }
                }
                else
                {
                    if ((chr & 0xC0) != 0x80)
                        return false;

                    cOctets--;
                }
            }

            if (cOctets > 0)
                return false;

            if (bAllAscii)
                return false;

            return true;
        }

        /// <summary>
        /// 分割字符串
        /// SplitString(filelist.ToString(), "\r\n");
        /// </summary>
        public static string[] SplitString(string strContent, string strSplit)
        {
            if (!string.IsNullOrEmpty(strContent))
            {
                if (strContent.IndexOf(strSplit) < 0)
                    return new string[] { strContent };

                return Regex.Split(strContent, Regex.Escape(strSplit), RegexOptions.IgnoreCase);
            }
            else
                return new string[0] { };
        }
        #endregion

        #region hisView
        delegate void SetLogCallback(string imgType, string logInfo);
        private void WriteLog(string imgType, string logInfo)
        {
            ListViewItem infoMsg = new ListViewItem();
            infoMsg.ImageKey = imgType;
            infoMsg.Text = logInfo;
            infoMsg.ToolTipText = logInfo;
            infoMsg.SubItems.Add(System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            if (hisView.InvokeRequired)
            {
                SetLogCallback logCall = new SetLogCallback(WriteLog);
                this.Invoke(logCall, new object[] { imgType, logInfo });
            }
            else
            {
                hisView.Items.Add(infoMsg);
            }
        }
        #endregion

        private void MainFrm_Load(object sender, EventArgs e)
        {
            button2.Enabled = false;
            WriteLog(ImgConst.SUCC, "初始化系统配置成功！");
        }
    }
    public class ImgConst
    {
        public const string INFO = "info";
        public const string SUCC = "succ";
        public const string WARN = "warn";

        public ImgConst()
        {
        }
    }
}
